/*!	 valuenode.h
**	 Valuenodes
**
**	Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
**	Copyright (c) 2008 Chris Moore
**	Copyright (c) 2011 Carlos López
**	Copyright (c) 2016 caryoscelus
**
**	This package is free software; you can redistribute it and/or
**	modify it under the terms of the GNU General Public License as
**	published by the Free Software Foundation; either version 2 of
**	the License, or (at your option) any later version.
**
**	This package is distributed in the hope that it will be useful,
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
**	General Public License for more details.
**
*/

#ifndef __SYNFIG_VALUENODE_H
#define __SYNFIG_VALUENODE_H

#include "vector.h"
#include "value.h"
#include "string.h"
#include "releases.h"
#include "exception.h"
#include "guid.h"
#include "paramdesc.h"
#include "interpolation.h"
#include "node.h"

#include <ETL/angle>
#include <ETL/handle>
#include <ETL/stringf>

#include <sigc++/signal.h>

#include <map>
#include <set>
#include <memory>

#define VALUENODE_CHECK_TYPE(type) 										\
	/* I don't think this ever happens - maybe remove this code? */		\
	if (get_type() == type_nil) {										\
		warning("%s:%d get_type() IS nil sometimes!",					\
				__FILE__, __LINE__);									\
		return false;													\
	}																	\
	if (get_type() != type_nil &&										\
		!(ValueBase::can_copy(value->get_type(), type)) &&				\
		!PlaceholderValueNode::Handle::cast_dynamic(value)) {			\
		error(_("%s:%d wrong type for %s: need %s but got %s"),			\
			  __FILE__, __LINE__,										\
			  link_local_name(i).c_str(),								\
			  type.description.local_name.c_str(),						\
			  value->get_type().description.local_name.c_str() );		\
		return false;													\
	}

#define VALUENODE_SET_VALUE(variable)									\
	variable = value;													\
	signal_child_changed()(i);											\
	signal_value_changed()();											\
	return true

#define CHECK_TYPE_AND_SET_VALUE(variable, type)						\
	VALUENODE_CHECK_TYPE(type)											\
	VALUENODE_SET_VALUE(variable)

namespace synfig
{

class Canvas;
class LinkableValueNode;
class Layer;
class ParamVocab;

/*!	\class ValueNode
**	 Base class for all Value Nodes
*/
class ValueNode : public synfig::Node
{
    friend class Layer;
    friend class LinkableValueNode;
    friend class ValueNode_Interface;



public:

    typedef etl::handle<ValueNode> Handle;

    typedef etl::loose_handle<ValueNode> LooseHandle;

    typedef etl::handle<const ValueNode> ConstHandle;

    typedef etl::rhandle<ValueNode> RHandle;

    static void breakpoint();



private:
    // The type of the Value Node
    // \see ValueBase
    Type *type;
    // The name of the Value Node. This is the string that is used in the
    // sif file to define the value type: i.e. <param name="amount">
    String name;
    // The canvas this Value Node belongs to
    etl::loose_handle<Canvas> canvas_;
    // The root canvas this Value Node belongs to
    etl::loose_handle<Canvas> root_canvas_;



private:

    //	ValueBase Changed
    sigc::signal<void> signal_value_changed_;

    //	Children Reordered
    sigc::signal<void, int*> signal_children_reordered_;

    //	Child Changed
    sigc::signal<void, int> signal_child_changed_;

    //	Child Removed
    sigc::signal<void, int> signal_child_removed_;

    //	Child Inserted
    sigc::signal<void, int> signal_child_inserted_;

    //	ID Changed
    sigc::signal<void> signal_id_changed_;



public:

    //	ValueBase Changed
    sigc::signal<void>& signal_value_changed()
    {
        return signal_value_changed_;
    }

    //	Children Reordered
    sigc::signal<void, int*>& signal_children_reordered()
    {
        return signal_children_reordered_;
    }

    //	Child Changed
    sigc::signal<void, int>& signal_child_changed()
    {
        return signal_child_changed_;
    }

    //	Child Removed
    sigc::signal<void, int>& signal_child_removed()
    {
        return signal_child_removed_;
    }

    //	Child Inserted
    sigc::signal<void, int>& signal_child_inserted()
    {
        return signal_child_inserted_;
    }

    //	ID Changed
    sigc::signal<void>& signal_id_changed()
    {
        return signal_id_changed_;
    }



protected:

    ValueNode(Type &type = type_nil);

public:

    virtual ~ValueNode();



public:

    // Returns the value of the ValueNode at time \a t
    virtual ValueBase operator()(Time /*t*/)const
    {
        return ValueBase();
    }

    // \internal Sets the id of the ValueNode
    void set_id(const String &x);

    // Returns the id of the ValueNode
    /*!	The ID is used for keeping track of a
    **	specific instance of a ValueNode. */
    const String &get_id()const
    {
        return name;
    }

    // Returns the name of the ValueNode type
    virtual String get_name()const = 0;

    // Returns the localized name of the ValueNode type
    virtual String get_local_name()const = 0;

    // Return a full description of the ValueNode and its parentage
    virtual String get_description(bool show_exported_name = true)const;

    String get_string()const;

    // Clones a Value Node
    virtual ValueNode::Handle clone(etl::loose_handle<Canvas> canvas, const GUID& deriv_guid = GUID())const = 0;

    // Returns \true if the Value Node has an ID (has been exported)
    bool is_exported()const
    {
        return !get_id().empty();
    }

    // Check recursively if \value_node_dest is a descendant of the Value Node
    bool is_descendant(ValueNode::Handle value_node_dest);

    // Returns the type of the ValueNode
    Type& get_type()const
    {
        return *type;
    }

    // Returns a handle to the parent canvas, if it has one.
    etl::loose_handle<Canvas> get_parent_canvas()const;

    // Returns a handle to the parent canvas, if it has one.
    etl::loose_handle<Canvas> get_root_canvas()const;

    // Returns a handle to the parent canvas, if it has one.
    etl::loose_handle<Canvas> get_non_inline_ancestor_canvas()const;

    // Sets the parent canvas for the Value Node
    void set_parent_canvas(etl::loose_handle<Canvas> x);

    // Sets the root canvas parent for the Value Node
    virtual void set_root_canvas(etl::loose_handle<Canvas> x);

    // Returns the relative ID of a Node when accessed form the \x Canvas
    String get_relative_id(etl::loose_handle<const Canvas> x)const;

    // Replaces the Value Node with a given one. It look up all its parents
    // remove it self from them and adds the given Value Node
    // Notice that it is called twice and the second time it uses
    // a replaceable handle to the Node
    // \see etl::rhandle
    int replace(etl::handle<ValueNode> x);

    // Get the default interpolation for Value Nodes
    virtual Interpolation get_interpolation()const
    {
        return INTERPOLATION_UNDEFINED;
    }
    // Set the default interpolation for Value Nodes
    virtual void set_interpolation(Interpolation /* i*/) { }

    // TODO: cache of values (we need to fix chain of signals 'changed' in LinkableValueNodes
    void get_values(std::set<ValueBase> &x) const;
    void get_value_change_times(std::set<Time> &x) const;
    void get_values(std::map<Time, ValueBase> &x) const;

    void calc_time_bounds(int &begin, int &end, Real &fps) const;
    void calc_values(std::map<Time, ValueBase> &x) const;
    void calc_values(std::map<Time, ValueBase> &x, int begin, int end) const;
    void calc_values(std::map<Time, ValueBase> &x, int begin, int end, Real fps) const;

    int time_to_frame(Time t);
    static int time_to_frame(Time t, Real fps);
    static void add_value_to_map(std::map<Time, ValueBase> &x, Time t, const ValueBase &v);

private:
    static void canvas_time_bounds(const Canvas &canvas, bool &found, Time &begin, Time &end, Real &fps);
    static void find_time_bounds(const Node &node, bool &found, Time &begin, Time &end, Real &fps);

protected:
    // Sets the type of the ValueNode
    void set_type(Type &t)
    {
        type = &t;
    }

    virtual void on_changed();

    virtual void get_values_vfunc(std::map<Time, ValueBase> &x) const;
}; // END of class ValueNode

/**	\class ValueNode_Interface */
class ValueNode_Interface
{
private:
    ValueNode &node_;

protected:
    explicit ValueNode_Interface(ValueNode &node): node_(node) { }

public:
    virtual ~ValueNode_Interface() { }
    ValueNode& node()
    {
        return node_;
    };
    const ValueNode& node() const
    {
        return node_;
    };

protected:
    void set_type(Type &t)
    {
        node().set_type(t);
    }
};

/*!	\class PlaceholderValueNode
**	Seems to be a Place to hold a Value Node temporarly.
*
* 	Doesn't seem to implement any functionality. Seems to be used when the
* 	value node cannot be created using the Const, Animated or Linkable
* 	Value Nodes.
*
*/
class PlaceholderValueNode : public ValueNode
{
public:
    typedef etl::handle<PlaceholderValueNode> Handle;
    typedef etl::loose_handle<PlaceholderValueNode> LooseHandle;
    typedef etl::handle<const PlaceholderValueNode> ConstHandle;
    typedef etl::rhandle<PlaceholderValueNode> RHandle;

private:

    PlaceholderValueNode(Type &type = type_nil);

public:

    virtual ValueBase operator()(Time t)const;

    virtual String get_name()const;

    virtual String get_local_name()const;

    String get_string()const;

    virtual ValueNode::Handle clone(etl::loose_handle<Canvas> canvas, const GUID& deriv_guid = GUID())const;

    static Handle create(Type &type = type_nil);

protected:
    virtual void get_times_vfunc(Node::time_set &/*set*/) const {}
}; // END of class PlaceholderValueNode

/*!	\class LinkableValueNode
**	 Specialized Class of Value Nodes that has links to other
** Value Nodes
*
* 	This Value Node is calculated based on a math calculation or a time
* 	evaluation of the linked Value Nodes. It is commonly known as
* 	Converted Value Nodes. The derived clases defines the behavior.
*/
class LinkableValueNode : public ValueNode
{
    friend class ValueNode;
public:

    typedef etl::handle<LinkableValueNode> Handle;

    typedef etl::loose_handle<LinkableValueNode> LooseHandle;

    typedef etl::handle<const LinkableValueNode> ConstHandle;

    typedef etl::rhandle<LinkableValueNode> RHandle;

    // The vocabulary of the children
    /*! \see synfig::Paramdesc
     */
    typedef ParamVocab Vocab;

public:
    LinkableValueNode(Type &type = type_nil):
        ValueNode(type) { }

protected:
    // Stores the Value Node \x in the sub parameter i after check if the
    // type is the same.
    // It has to be defined by the derived class.
    virtual bool set_link_vfunc(int i, ValueNode::Handle x) = 0;

    // Frees all the subparameters of the Linkable Value Node.
    // Used by the derived classed destructors.
    void unlink_all();

public:

    // Returns the number of linked Value Nodes
    virtual int link_count()const;

    // Returns the local name of the 'i' linked Value Node
    virtual String link_local_name(int i)const;

    // Returns the name of the 'i' linked Value Node
    virtual String link_name(int i)const;

    // Returns the child index Value Node based on the name
    virtual int get_link_index_from_name(const String &name)const;

    // Clones a Value Node
    virtual ValueNode::Handle clone(etl::loose_handle<Canvas> canvas, const GUID& deriv_guid = GUID())const;

    // Sets a new Value Node link by its index
    bool set_link(int i, ValueNode::Handle x);
    // Sets a new Value Node link by its name
    bool set_link(const String &name, ValueNode::Handle x)
    {
        return set_link(get_link_index_from_name(name), x);
    }

    // Returns a Loose Handle to the Value Node based on the link's index
    ValueNode::LooseHandle get_link(int i)const;
    // Returns a Loose Handle to the Value Node based on the link's name
    ValueNode::LooseHandle get_link(const String &name)const
    {
        return get_link(get_link_index_from_name(name));
    }
    // Return a full description of the linked ValueNode given by the index
    String get_description(int index = -1, bool show_exported_name = true)const;
    // Return a full description of the linked ValueNode given by the index
    // Proper overload of the inherited function
    String get_description(bool show_exported_name = true)const;

    // Gets the children vocabulary for linkable value nodes
    virtual Vocab get_children_vocab()const;

    virtual void set_root_canvas(etl::loose_handle<Canvas> x);

protected:
    // Member to store the children vocabulary
    Vocab children_vocab;
    // Sets the type of the ValueNode
    void set_type(Type &t)
    {
        ValueNode::set_type(t);
    }

    // Virtual member to get the linked Value Node Handle
    virtual ValueNode::LooseHandle get_link_vfunc(int i)const = 0;

    // Wrapper for new operator, used by clone()
    virtual LinkableValueNode* create_new()const = 0;

    // Returns the cached times values for all the children (linked Value Nodes)
    virtual void get_times_vfunc(Node::time_set &set) const;

    // Pure Virtual member to get the children vocabulary
    virtual Vocab get_children_vocab_vfunc()const = 0;

    // Virtual memebr to set the children vocabulary to a given value
    virtual void set_children_vocab(const Vocab& rvocab);

    virtual void get_values_vfunc(std::map<Time, ValueBase> &x) const;
}; // END of class LinkableValueNode

/*!	\class ValueNodeList
**	 A searchable value_node list container
**	\warning Do not confuse with ValueNode_DynamicList!
*
*  Used by Canvas class to access to the exported value nodes.
*/
class ValueNodeList : public std::list<ValueNode::RHandle>
{
    int placeholder_count_;
public:
    ValueNodeList();

    // Finds the ValueNode in the list with the given \a name
    /*!	\return If found, returns a handle to the ValueNode.
    **		Otherwise, returns an empty handle.
    */
    ValueNode::Handle find(const String &name, bool might_fail);

    // Finds the ValueNode in the list with the given \a name
    /*!	\return If found, returns a handle to the ValueNode.
    **		Otherwise, returns an empty handle.
    */
    ValueNode::ConstHandle find(const String &name, bool might_fail)const;

    // Removes the \a value_node from the list
    bool erase(ValueNode::Handle value_node);

    // \writeme
    bool add(ValueNode::Handle value_node);

    // \writeme
    bool count(const String &id)const;

    // Similar to find, but will create a placeholder value_node if it cannot be found.
    ValueNode::Handle surefind(const String &name);

    // Removes any value_nodes with reference counts of 1.
    void audit();

    // Placeholder Count
    int placeholder_count()const
    {
        return placeholder_count_;
    }
};

ValueNode::LooseHandle find_value_node(const GUID& guid);

}; // END of namespace synfig

#endif